
package com.jf.cloud.search.feign;


import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.jf.cloud.api.dto.EsPageDTO;
import com.jf.cloud.api.feign.SearchSpuFeignClient;
import com.jf.cloud.api.vo.EsPageVO;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.constant.StatusEnum;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.product.dto.ProductSearchDTO;
import com.jf.cloud.common.product.dto.ProductSearchLimitDTO;
import com.jf.cloud.common.product.vo.search.ProductSearchVO;
import com.jf.cloud.common.product.vo.search.SpuAdminVO;
import com.jf.cloud.common.product.vo.search.SpuSearchVO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.search.builder.ProductSearchRequestBuilder;
import com.jf.cloud.search.constant.EsConstant;
import com.jf.cloud.search.manager.ProductSearchManager;
import com.jf.cloud.search.util.EsSearchUtil;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Hidden;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 商品搜索feign连接
 * @author zz
 * @date 2020/12/07
 */
@RestController
@Hidden
public class SearchSpuFeignController implements SearchSpuFeignClient {

    private static final Logger log = LoggerFactory.getLogger(SearchSpuFeignController.class);

    @Autowired
    private ProductSearchManager productSearchManager;
    @Autowired
    private ProductSearchRequestBuilder productSearchRequestBuilder;

    @Override
    public ServerResponseEntity<EsPageVO<ProductSearchVO>> search(@Valid ProductSearchDTO productSearch) {
        Integer lang = I18nMessage.getLang();
        EsPageDTO pageDTO = new EsPageDTO();
        pageDTO.setPageNum(productSearch.getPageNum());
        pageDTO.setPageSize(productSearch.getPageSize());
        return ServerResponseEntity.success(productSearchManager.spuPage(pageDTO, productSearch));
    }

    @Override
    public ServerResponseEntity<List<SpuSearchVO>> listSpuBySpuIds(List<Long> spuIds) {
        if (CollUtil.isEmpty(spuIds)) {
            return ServerResponseEntity.success(new ArrayList<>());
        }
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        productSearchDTO.setSpuIds(spuIds);
        List<SpuSearchVO> list = productSearchManager.listSpuBySpuIds(productSearchDTO);
        return ServerResponseEntity.success(list);
    }


    @Override
    public ServerResponseEntity<EsPageVO<ProductSearchVO>> spuPage(Integer pageNum, Integer pageSize, Long shopId) {
        EsPageDTO pageDTO = new EsPageDTO();
        pageDTO.setPageNum(pageNum);
        pageDTO.setPageSize(pageSize);
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        // 平台id则搜索整个平台的商品
        if (!Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            productSearchDTO.setShopId(shopId);
        }
        EsPageVO<ProductSearchVO> page = productSearchManager.spuPage(pageDTO, productSearchDTO);
        return ServerResponseEntity.success(page);
    }

    @Override
    public ServerResponseEntity<EsPageVO<SpuAdminVO>> adminPage(@RequestBody ProductSearchDTO productSearch) {
        EsPageDTO pageDTO = new EsPageDTO();
        pageDTO.setPageNum(productSearch.getPageNum());
        pageDTO.setPageSize(productSearch.getPageSize());
        productSearch.setFetchSource(Objects.isNull(productSearch.getShopId()) ? EsConstant.PLATFORM_FETCH_SOURCE : EsConstant.SHOP_FETCH_SOURCE);
        productSearch.setKeyword(productSearch.getKeyword());
        EsPageVO<SpuAdminVO> adminPage = productSearchManager.adminPage(pageDTO, productSearch);
        return ServerResponseEntity.success(adminPage);
    }

    @Override
    public ServerResponseEntity<List<SpuSearchVO>> limitSpuList(ProductSearchLimitDTO productSearchLimitDTO) {
        return ServerResponseEntity.success(productSearchManager.limitSpuList(productSearchLimitDTO));
    }

    @Override
    public ServerResponseEntity<Map<Long, List<SpuSearchVO>>> limitSpuMap(ProductSearchLimitDTO productSearchLimitDTO) {
        return ServerResponseEntity.success(productSearchManager.limitSpuMap(productSearchLimitDTO));
    }

    @Override
    public ServerResponseEntity<List<SpuSearchVO>> listNotDeleteSpu(List<Long> spuIds) {
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        productSearchDTO.setSpuIds(spuIds);
        productSearchDTO.setFetchSource(EsConstant.SHOP_FETCH_SOURCE);
        return ServerResponseEntity.success(productSearchManager.listSpuBySpuIds(productSearchDTO));
    }

    @Override
    public ServerResponseEntity<List<SpuSearchVO>> simpleList(ProductSearchDTO productSearchDTO) {
        productSearchDTO.setFetchSource(EsConstant.SIMPLE_FETCH_SOURCE);
        List<SpuSearchVO> list = productSearchManager.listSpuBySpuIds(productSearchDTO);
        return ServerResponseEntity.success(list);
    }

    @Override
    public ServerResponseEntity<List<SpuSearchVO>> listExcelPlatformSpu(ProductSearchDTO productSearchDTO) {
        productSearchDTO.setFetchSource(EsConstant.PLATFORM_EXPORT_FETCH_SOURCE);
        productSearchDTO.setAppDisplay(Boolean.FALSE);
        String scrollId = null;
        List<SpuSearchVO> result = new ArrayList<>();
        // 设置查询超时时间
        Scroll scroll = new Scroll(TimeValue.timeValueMinutes(5L));
        SearchRequest searchRequest = productSearchRequestBuilder.buildScrollSearchRequest(productSearchDTO, scroll);
        try {
            // 进行第一次滚动查询
            SearchResponse searchResponse = EsSearchUtil.search(searchRequest);
            scrollId = searchResponse.getScrollId();

            //记录要滚动的ID
            //滚动查询部分，将从第1001笔数据开始取
            SearchHit[] hitsScroll = searchResponse.getHits().getHits();
            for(SearchHit searchHit : hitsScroll){
                SpuSearchVO spuSearchVO = JSON.parseObject(searchHit.getSourceAsString(), SpuSearchVO.class);
                result.add(spuSearchVO);
            }
            while (hitsScroll != null && hitsScroll.length > 0) {
                //构造滚动查询条件
                SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
                searchScrollRequest.scroll(scroll);
                searchResponse = EsSearchUtil.scroll(searchScrollRequest);
                scrollId = searchResponse.getScrollId();
                hitsScroll = searchResponse.getHits().getHits();

                for(SearchHit searchHit : searchResponse.getHits().getHits()){
                    SpuSearchVO spuSearchVO = JSON.parseObject(searchHit.getSourceAsString(), SpuSearchVO.class);
                    result.add(spuSearchVO);
                }
            }
        } catch (Exception e) {
            log.error("获取平台商品异常:" + e);
            throw new LuckException("获取平台商品异常");
        } finally {
            if (Objects.nonNull(scrollId)) {
                //清除滚动，否则影响下次查询
                EsSearchUtil.clearScroll(scrollId);
            }
        }
        return ServerResponseEntity.success(result);
    }

    @Override
    public ServerResponseEntity<?> checkSpuStatus(List<Long> spuIds) {
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        productSearchDTO.setSpuIds(spuIds);
        productSearchDTO.setFetchSource(EsConstant.SHOP_FETCH_SOURCE);
        List<SpuSearchVO> spuList = productSearchManager.listSpuBySpuIds(productSearchDTO);
        spuList.forEach(spuVO -> {
            if (!Objects.equals(spuVO.getSpuStatus(), StatusEnum.ENABLE.value())) {
                throw new LuckException(ResponseEnum.SPU_STATUS_ERROR, spuVO.getSpuId());
            }
        });
        return ServerResponseEntity.success();
    }
}
